home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / others / ole_101.zip / SCHMOO.ZIP / POLYLINE.C < prev    next >
C/C++ Source or Header  |  1992-04-13  |  17KB  |  594 lines

  1. /*
  2.  * POLYLINE.C
  3.  *
  4.  * Window procedure for the polyline drawing window and support functions.
  5.  * This window is not complicated.  On creation it allocates a block of
  6.  * memory for a POLYLINE structure that contains 20 POINTs.  We do not
  7.  * attempt to reallocate this array at all just to maintain simplicity.
  8.  * This sample is to demonstrate OLE, not LocalReAlloc.
  9.  *
  10.  * Copyright(c) Microsoft Corp. 1992 All Rights Reserved
  11.  */
  12.  
  13.  
  14. #include <windows.h>
  15. #include "schmoo.h"
  16.  
  17. /*
  18.  * HACK:  To fix some Invalid hDC rips, we need to supress certain
  19.  * operations on metafile DC's: GetMapMode, DPtoLP, LPtoDP.
  20.  * We use this flag to indicate supression.
  21.  */
  22. BOOL fMetaDC=FALSE;
  23.  
  24.  
  25.  
  26. /*
  27.  * HPolylineWindowCreate
  28.  *
  29.  * Purpose:
  30.  *  Creates a Polyline window within the client area of hWndParent.
  31.  *
  32.  * Parameters:
  33.  *  hWndParent      HWND of the parent window.
  34.  *  hInstance       HANDLE of the application instance.
  35.  *
  36.  * Return Value:
  37.  *  HWND            Result of the CreateWindowEx call.
  38.  *
  39.  */
  40.  
  41. HWND FAR PASCAL HPolylineWindowCreate(HWND hWndParent, HANDLE hInstance)
  42.     {
  43.     RECT        rc;
  44.     HWND        hWndT;
  45.  
  46.     /*
  47.      * Create the secondary window for this application in a
  48.      * shrunk client area.
  49.      */
  50.     GetClientRect(hWndParent, &rc);
  51.     InflateRect(&rc, -8, -8);
  52.  
  53.     //Create the editor window.
  54.     hWndT=CreateWindowEx(WS_EX_NOPARENTNOTIFY,
  55.                          rgpsz[IDS_CLASSPOLYLINE],
  56.                          rgpsz[IDS_CLASSPOLYLINE],
  57.                          WS_CHILD | WS_VISIBLE,
  58.                          rc.left, rc.top,
  59.                          rc.right-rc.left, rc.bottom-rc.top,
  60.                          hWndParent, ID_POLYLINE, hInstance, NULL);
  61.  
  62.     return hWndT;
  63.     }
  64.  
  65.  
  66.  
  67.  
  68.  
  69. /*
  70.  * PolylineWndProc
  71.  *
  72.  * Purpose:
  73.  *  Window procedure for the polyline drawing window.
  74.  *
  75.  * Parameters:
  76.  *  The standard.
  77.  *
  78.  * Return Value:
  79.  *  Standard.
  80.  */
  81.  
  82. LONG FAR PASCAL PolylineWndProc(HWND hWnd, UINT iMsg, UINT wParam, LONG lParam)
  83.     {
  84.     PAINTSTRUCT     ps;
  85.     HDC             hDC;
  86.     HWND            hWndParent;
  87.     HANDLE          hMem;
  88.     LPPOLYLINE      ppl;
  89.     DWORD           dwRet=0L;
  90.  
  91.     ppl=(LPPOLYLINE)(PSTR)GetWindowWord(hWnd, 0);
  92.  
  93.     if (WM_USER <= iMsg)
  94.         return LPolylineUserMessage(hWnd, iMsg, wParam, lParam, ppl);
  95.  
  96.  
  97.     switch (iMsg)
  98.         {
  99.  
  100.         case WM_NCCREATE:
  101.             hMem=LocalAlloc(LPTR, CBPOLYLINE);
  102.  
  103.             if (NULL==hMem)
  104.                 return 0L;
  105.  
  106.             SetWindowWord(hWnd, 0, hMem);
  107.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  108.  
  109.  
  110.         case WM_NCDESTROY:
  111.             hMem=GetWindowWord(hWnd, 0);
  112.             LocalFree(hMem);
  113.             return DefWindowProc(hWnd, iMsg, wParam, lParam);
  114.  
  115.  
  116.         case WM_CREATE:
  117.             //Stash away the current window rectangle.
  118.             GetClientRect(hWnd, &ppl->rc);
  119.  
  120.             ppl->wVerMaj=VERSIONMAJOR;
  121.             ppl->wVerMin=VERSIONMINOR;
  122.             ppl->cPoints=0;
  123.             break;
  124.  
  125.  
  126.         case WM_PAINT:
  127.             hDC=BeginPaint(hWnd, &ps);
  128.  
  129.             if (0!=ppl->cPoints)
  130.                 {
  131.                 ppl->fDrawEntire=TRUE;
  132.                 PolylineDraw(hWnd, hDC, ppl);
  133.                 }
  134.  
  135.             EndPaint(hWnd, &ps);
  136.             break;
  137.  
  138.         case WM_LBUTTONDOWN:
  139.             //Stop if we are already at the limit.
  140.             if (CPOLYLINEPOINTS==ppl->cPoints)
  141.                 {
  142.                 MessageBeep(0);
  143.                 break;
  144.                 }
  145.  
  146.             //Stuff the new point in the array.
  147.             ppl->rgpt[ppl->cPoints].x=LOWORD(lParam);
  148.             ppl->rgpt[ppl->cPoints].y=HIWORD(lParam);
  149.  
  150.             ppl->cPoints++;
  151.  
  152.             //Draw the lines to this new point only.
  153.             hDC=GetDC(hWnd);
  154.  
  155.             ppl->fDrawEntire=FALSE;
  156.             PolylineDraw(hWnd, hDC, ppl);
  157.  
  158.             ReleaseDC(hWnd, hDC);
  159.  
  160.             hWndParent=GetParent(hWnd);
  161.             SendMessage(hWndParent, WM_COMMAND,
  162.                         ID_POLYLINE, MAKELONG(hWnd, PLN_POINTCHANGE));
  163.             break;
  164.  
  165.  
  166.         default:
  167.             dwRet=DefWindowProc(hWnd, iMsg, wParam, lParam);
  168.             break;
  169.         }
  170.  
  171.     return dwRet;
  172.     }
  173.  
  174.  
  175.  
  176.  
  177.  
  178.  
  179.  
  180. /*
  181.  * LPolylineUserMessage
  182.  *
  183.  * Purpose:
  184.  *  Handles all window-specific messages WM_USER and greater,
  185.  *  for the Polyline window:
  186.  *
  187.  *  PLM_RECTSET:        Changes the size of the window and scales the
  188.  *                      data points.
  189.  *
  190.  *  PLM_POLYLINESET:    Sets the current data points and the rectangle
  191.  *                      used to generate the figure.
  192.  *
  193.  *  PLM_POLYLINEGET:    Retrieves the current data points and rectangle
  194.  *                      used to generate the figure.
  195.  *
  196.  *  PLM_POLYLINENEW:    Resets the data points to defaults, meaning
  197.  *                      a blank figure.
  198.  *
  199.  *  PLM_BACKUPUNDO:     Backs the figure up one point.
  200.  *
  201.  *  PLM_BITMAPGET:      Retrieves a bitmap (DDB) of the current image.
  202.  *
  203.  *  PLM_METAFILEGET:    Retrieves a metafile for the current image.
  204.  *
  205.  *  PLM_METAFILEPICTGET:Retrieves a METAFILEPICT structure of the image for
  206.  *                      use in clipboard I/O.
  207.  *
  208.  * Parameters:
  209.  *  hWnd            HWND of the Polyline window.
  210.  *  iMsg            WORD message to process.
  211.  *  wParam          WORD parameter of the message.
  212.  *  lParam          LONG parameter of the message.
  213.  *  ppl            LPPOLYLINE to the window's extra data structure.
  214.  *
  215.  * Return Value:
  216.  *  DWORD           Value to return from the window procedure
  217.  *                  that recieved the message.
  218.  */
  219.  
  220. DWORD PASCAL LPolylineUserMessage(HWND hWnd, WORD iMsg, WORD wParam,
  221.                                   LONG lParam, LPPOLYLINE ppl)
  222.     {
  223.     DWORD           dwRet=0L;
  224.     HWND            hWndParent;
  225.     HBITMAP         hBmp, hBmpT;
  226.     HDC             hDC, hMemDC;
  227.     LPPOLYLINE      pplT;
  228.     LPMETAFILEPICT  pMF;
  229.     HANDLE          hMem;
  230.     HANDLE          hMF;
  231.     RECT            rc;
  232.     LPRECT          pRect;
  233.     WORD            i;
  234.     DWORD           dw, cx, cy, cxT, cyT;
  235.  
  236.     hWndParent=GetParent(hWnd);
  237.  
  238.     switch (iMsg)
  239.         {
  240.         case PLM_RECTSET:
  241.             /*
  242.              * Resize the window to the given size, letting WM_SIZE handlers
  243.              * take care of the rest.
  244.              */
  245.             pRect=(LPRECT)lParam;
  246.  
  247.             /*
  248.              * Scale all the current points to new dimensions.  ppl->rc
  249.              * has the old dimensions, pRect points to the new.  We
  250.              * force each of cx and cy to 1 if they are zero to prevent
  251.              * exceptions.
  252.              */
  253.  
  254.             rc=ppl->rc;
  255.             cxT=rc.right  - rc.left;
  256.             cyT=rc.bottom - rc.top;
  257.  
  258.             ppl->rc=*pRect;
  259.             cx=pRect->right  - pRect->left;
  260.             cy=pRect->bottom - pRect->top;
  261.  
  262.             //Prevent crashes
  263.             if (0L==cxT)
  264.                 cxT=1;
  265.  
  266.             if (0L==cyT)
  267.                 cyT=1;
  268.  
  269.             //Loop through each point, scaling if necessary.
  270.             for (i=0; i< ppl->cPoints; i++)
  271.                 {
  272.                 //Must use DWORD to insure proper scaling.
  273.                 if (cx!=cxT)
  274.                     {
  275.                     dw=((DWORD)ppl->rgpt[i].x*cx);
  276.                     ppl->rgpt[i].x=(WORD)(dw/cxT);
  277.                     }
  278.  
  279.                 if (cy!=cyT)
  280.                     {
  281.                     dw=((DWORD)ppl->rgpt[i].y*cy);
  282.                     ppl->rgpt[i].y=(WORD)(dw/cyT);
  283.                     }
  284.                 }
  285.  
  286.             SetWindowPos(hWnd, NULL, pRect->left, pRect->top, (WORD)cx, (WORD)cy,
  287.                          SWP_NOMOVE | SWP_NOZORDER);
  288.  
  289.             //Check if we need to notify the parent.
  290.             if (0!=wParam)
  291.                 {
  292.                 SendMessage(hWndParent, WM_COMMAND,
  293.                             ID_POLYLINE, MAKELONG(hWnd, PLN_SIZECHANGE));
  294.                 }
  295.  
  296.             //Insure repaint
  297.             InvalidateRect(hWnd, NULL, TRUE);
  298.             UpdateWindow(hWnd);
  299.             break;
  300.  
  301.  
  302.         case PLM_POLYLINESET:
  303.             /*
  304.              * Copy the structure in lParam to ppl and repaint to
  305.              * reflect the new point set.  Note that unlike the
  306.              * PLM_RECTSET message, we do no scaling, assuming that
  307.              * the rectangle in the POLYLINE structure is appropriate
  308.              * for the data.
  309.              */
  310.             pplT=(LPPOLYLINE)lParam;
  311.             *ppl=*pplT;
  312.  
  313.             //Resize this window to fit the data and notify the parent.
  314.             SetWindowPos(hWnd, NULL, ppl->rc.left, ppl->rc.top,
  315.                          ppl->rc.right-ppl->rc.left, ppl->rc.bottom-ppl->rc.top,
  316.                          SWP_NOMOVE | SWP_NOZORDER);
  317.  
  318.             if (0!=wParam)
  319.                 {
  320.                 SendMessage(hWndParent, WM_COMMAND,
  321.                             ID_POLYLINE, MAKELONG(hWnd, PLN_SIZECHANGE));
  322.                 }
  323.  
  324.             //Insure a repaint.
  325.             InvalidateRect(hWnd, NULL, TRUE);
  326.             UpdateWindow(hWnd);
  327.             break;
  328.  
  329.  
  330.         case PLM_POLYLINEGET:
  331.             //Copy the structure in ppl to lParam.  No repaint needed.
  332.             pplT=(LPPOLYLINE)lParam;
  333.             *pplT=*ppl;
  334.             break;
  335.  
  336.  
  337.         case PLM_POLYLINENEW:
  338.             //Clean out the POLYLINE structure and repaint the window.
  339.             for (i=0; i< CPOLYLINEPOINTS; i++)
  340.                 {
  341.                 ppl->rgpt[i].x=0;
  342.                 ppl->rgpt[i].y=0;
  343.                 }
  344.  
  345.             ppl->cPoints=0;
  346.  
  347.             InvalidateRect(hWnd, NULL, TRUE);
  348.             UpdateWindow(hWnd);
  349.             break;
  350.  
  351.  
  352.         case PLM_BACKUPUNDO:
  353.             //Decrement the number of active points and repaint.
  354.             if (ppl->cPoints > 0)
  355.                 {
  356.                 ppl->cPoints--;
  357.                 InvalidateRect(hWnd, NULL, TRUE);
  358.                 UpdateWindow(hWnd);
  359.                 }
  360.  
  361.             //Notify parent window of the change.
  362.             SendMessage(hWndParent, WM_COMMAND,
  363.                         ID_POLYLINE, MAKELONG(hWnd, PLN_POINTCHANGE));
  364.             break;
  365.  
  366.  
  367.         case PLM_BITMAPGET:
  368.             /*
  369.              * Create and return a bitmap of the window contents.
  370.              * The bitmap is the size of the POLYLINE edit window.
  371.              */
  372.  
  373.             hDC=GetDC(hWnd);
  374.             hMemDC=CreateCompatibleDC(hDC);
  375.  
  376.             GetClientRect(hWnd, &rc);
  377.             hBmp=CreateCompatibleBitmap(hDC, rc.right, rc.bottom);
  378.  
  379.             if (NULL!=hBmp)
  380.                 {
  381.                 //Draw the POLYLINE into the bitmap.
  382.                 hBmpT=SelectObject(hMemDC, hBmp);
  383.  
  384.                 ppl->fDrawEntire=TRUE;
  385.                 PolylineDraw(hWnd, hMemDC, ppl);
  386.                 ppl->fDrawEntire=FALSE;
  387.  
  388.                 SelectObject(hMemDC, hBmpT);
  389.                 }
  390.  
  391.             DeleteDC(hMemDC);
  392.             ReleaseDC(hWnd, hDC);
  393.  
  394.             //Return the created bitmap handle.
  395.             dwRet=MAKELONG(hBmp, 0);
  396.             break;
  397.  
  398.  
  399.         case PLM_METAFILEGET:
  400.             //Create a memory metafile and return its handle.
  401.             hDC=(HDC)CreateMetaFile(NULL);
  402.             hMF=NULL;
  403.  
  404.             if (NULL!=hDC)
  405.                 {
  406.                 /*
  407.                  * This is absolutely essential to the metafile so it
  408.                  * can be scaled in the clipboard and any destination
  409.                  * application.
  410.                  */
  411.                 fMetaDC=TRUE;
  412.                 SetMapMode(hDC, MM_ANISOTROPIC);
  413.                 GetClientRect(hWnd, &rc);
  414.                 SetWindowOrg(hDC, 0, 0);
  415.                 SetWindowExt(hDC, rc.right, rc.bottom);
  416.  
  417.                 ppl->fDrawEntire=TRUE;
  418.                 PolylineDraw(hWnd, hDC, ppl);
  419.                 ppl->fDrawEntire=FALSE;
  420.  
  421.                 hMF=CloseMetaFile(hDC);
  422.                 fMetaDC=FALSE;
  423.                 }
  424.  
  425.             dwRet=MAKELONG(hMF, 0);
  426.             break;
  427.  
  428.  
  429.         case PLM_METAFILEPICTGET:
  430.             /*
  431.              * Create a METAFILEPICT structure for the clipboard.
  432.              * First attempt to get a metafile.
  433.              */
  434.             lParam=SendMessage(hWnd, PLM_METAFILEGET, 0, 0L);
  435.             hMF=LOWORD(lParam);
  436.  
  437.             if (NULL==hMF)
  438.                 break;
  439.  
  440.             //Allocate the METAFILEPICT structure.
  441.             hMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(METAFILEPICT));
  442.  
  443.             if (NULL==hMem)
  444.                 {
  445.                 DeleteMetaFile(hMF);
  446.                 break;
  447.                 }
  448.  
  449.             /*
  450.              * Global lock only fails in PMODE if the selector is invalid
  451.              * (like it was discarded) or references a 0 length segment,
  452.              * neither of which can happen here.
  453.              */
  454.             pMF=(LPMETAFILEPICT)GlobalLock(hMem);
  455.  
  456.             pMF->hMF=hMF;
  457.             pMF->mm=MM_ANISOTROPIC;             //Required by OLE libraries.
  458.  
  459.             //Insert the extents in MM_HIMETRIC units.
  460.             GetClientRect(hWnd, &rc);
  461.  
  462.             RectConvertToHiMetric(hWnd, &rc);     //Found in CLIP.C
  463.             pMF->xExt=rc.right;
  464.             pMF->yExt=rc.bottom;
  465.  
  466.             GlobalUnlock(hMem);
  467.  
  468.             dwRet=MAKELONG(hMem, 0);
  469.             break;
  470.  
  471.  
  472.         default:
  473.             break;
  474.         }
  475.  
  476.     return dwRet;
  477.     }
  478.  
  479.  
  480.  
  481.  
  482.  
  483.  
  484. /*
  485.  * PolylineDraw
  486.  *
  487.  * Purpose:
  488.  *  Paints the current line in the polyline window.
  489.  *
  490.  * Parameters:
  491.  *  hWnd            HWND of the polyline window.
  492.  *  hDC             HDC to draw on, could be a metafile or printer DC.
  493.  *  ppl            LPPOLYLINE to the polyline structure.
  494.  *
  495.  * Return Value:
  496.  *  none
  497.  */
  498.  
  499. void PASCAL PolylineDraw(HWND hWnd, HDC hDC, LPPOLYLINE ppl)
  500.     {
  501.  
  502.     HBRUSH          hBrush, hBrushT;
  503.     HPEN            hPen, hPenT;
  504.     WORD            i, j;
  505.     WORD            nMM;
  506.     POINT           pt;
  507.     RECT            rc;
  508.     COLORREF        cr;
  509.  
  510.  
  511.     GetClientRect(hWnd, &rc);
  512.  
  513.     //Get the line color.
  514.     cr=GetSysColor(COLOR_WINDOWTEXT);
  515.  
  516.     /*
  517.      * If the mapping mode is not MM_TEXT, convert the points to
  518.      * whatever mapping mode in in effect before drawing.
  519.      * This specifically supports metafiles in MM_ANISOTROPIC.
  520.      */
  521.     nMM=fMetaDC ? MM_TEXT : GetMapMode(hDC);
  522.  
  523.     if (MM_TEXT!=nMM)
  524.         DPtoLP(hDC, ppl->rgpt, ppl->cPoints);
  525.  
  526.     hPen=CreatePen(PS_SOLID, 1, cr);
  527.     hPenT=SelectObject(hDC, hPen);
  528.  
  529.     hBrush=CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  530.     hBrushT=SelectObject(hDC, hBrush);
  531.  
  532.     /*
  533.      * Either draw the entire figure or just a single point.  The
  534.      * entire figure also includes erasing the background completely,
  535.      * since hDC may be a metafile DC.  Drawing a single point just
  536.      * updates the figure for that new point.
  537.      */
  538.     if (ppl->fDrawEntire)
  539.         {
  540.         //Erase the background for bitmaps and metafiles.
  541.         SelectObject(hDC, GetStockObject(NULL_PEN));
  542.         Rectangle(hDC, rc.left, rc.top, rc.right+1, rc.bottom+1);
  543.         SelectObject(hDC, hPen);
  544.  
  545.  
  546.         /*
  547.          * If we are drawing the entire figure, then loop through each
  548.          * point drawing a line to each successive point.
  549.          */
  550.  
  551.         for (i=0; i < ppl->cPoints; i++)
  552.             {
  553.             for (j=i; j < ppl->cPoints; j++)
  554.                 {
  555.                 MoveTo(hDC, ppl->rgpt[i].x, ppl->rgpt[i].y);
  556.                 LineTo(hDC, ppl->rgpt[j].x, ppl->rgpt[j].y);
  557.                 }
  558.             }
  559.         }
  560.     else
  561.         {
  562.         /*
  563.          * If we are only drawing the last point, just cycle once
  564.          * through previous points.
  565.          */
  566.  
  567.         //Get the last point entered in the array.
  568.         j=ppl->cPoints-1;
  569.         pt=ppl->rgpt[j];
  570.  
  571.         for (i=0; i < j; i++)
  572.             {
  573.             MoveTo(hDC, pt.x, pt.y);
  574.             LineTo(hDC, ppl->rgpt[i].x, ppl->rgpt[i].y);
  575.             }
  576.         }
  577.  
  578.     //If we only had one point, draw a dot to indicate it's position.
  579.     if (1==ppl->cPoints)
  580.         SetPixel(hDC, ppl->rgpt[0].x, ppl->rgpt[0].y, cr);
  581.  
  582.  
  583.  
  584.     //Restore original points.
  585.     if (MM_TEXT!=nMM)
  586.         LPtoDP(hDC, ppl->rgpt, ppl->cPoints);
  587.  
  588.     SelectObject(hDC, hPenT);
  589.     SelectObject(hDC, hBrushT);
  590.     DeleteObject(hBrush);
  591.     DeleteObject(hPen);
  592.     return;
  593.     }
  594.